#include <fs.h>
#include <fs/ramfs.h>

static volatile u32 inode_next_id = 0;

extern const inode_ops ramfs_inode_ops;

int ramfs_mkdir(inode_t* this, dentry_t* dentry) {
    inode_t* inode = fs_alloc_inode(dentry->sb);
    inode->type = FS_DIR;

    fs_inode_addhash(inode);
    fs_assign_inode(dentry, inode);

    return 0;
}

int ramfs_create(inode_t* this, dentry_t* dentry) {
    inode_t* inode = fs_alloc_inode(dentry->sb);
    inode->type = FS_FILE;

    fs_inode_addhash(inode);
    fs_assign_inode(dentry, inode);

    return 0;
}

void ramfs_inode_init(sb_t* vsb, inode_t* inode) {
    inode->id = inode_next_id++;
    inode->iops = &ramfs_inode_ops;
}

int ramfs_mount(sb_t* sb, dentry_t* mount_point) {
    sb->init_inode = ramfs_inode_init;

    inode_t* inode = fs_alloc_inode(sb);
    inode->type = FS_DIR;

    fs_inode_addhash(inode);
    fs_assign_inode(mount_point, inode);

    return 0;
}

int ramfs_umount(sb_t* vsb) {
    return 0;
}

int ramfs_readdir(file_t* file, dirent_t* dirent) {
    u32 i = 2;
    dentry_t* pos, * n;
    list_for_each(pos, n, &file->dentry->children, siblings) {
        if (i++ < dirent->d_offset) {
            continue;
        }
        dirent_assign(dirent, pos->name.val, pos->name.len, fs_get_dtype(pos->inode->type));
        return 1;
    }
    return 0;
}

void ramfs_init() {
    fs_t* ramfs = fs_alloc_fs("ramfs", 5);
    ramfs->mount = ramfs_mount;
    ramfs->umount = ramfs_umount;

    fs_register(ramfs);
}

const inode_ops ramfs_inode_ops = {
    .mkdir = ramfs_mkdir,
    .rmdir = default_inode_rmdir,
    .lookup = default_inode_lookup,
    .create = ramfs_create,
    .open = default_inode_open
};

const f_ops ramfs_file_ops = {
    .read = default_file_read,
    .write = default_file_write,
    .readdir = ramfs_readdir
};